using System;
using System.Collections.Generic;
// using System.Linq;
using UnityEngine;
using ZLinq;
namespace GGameFramework.Core.Pool
{
    /// <summary>
    /// 对象池标识类型
    /// </summary>
    public enum PoolType
    {
        /// <summary>
        /// 引用类型对象池：按脚本类型分类，用于任何引用类型对象
        /// </summary>
        ReferencePool,
        
        /// <summary>
        /// GameObject对象池：按预制体实例ID分类，专门用于Unity GameObject
        /// </summary>
        GameObjectPool
    }
    
    /// <summary>
    /// 统一对象池管理器
    /// </summary>
    public class PoolManager : FrameworkModule
    {
        internal override int Priority => (int)FrameworkSystemPriority.Pool;
        
        // 引用类型对象池：按脚本类型分类
        private readonly Dictionary<Type, IObjectPool> _referencePools = new Dictionary<Type, IObjectPool>();
        
        // GameObject对象池：按预制体实例ID分类
        private readonly Dictionary<int, IObjectPool> _gameObjectPools = new Dictionary<int, IObjectPool>();
        
        #region 引用类型对象池操作
        
        /// <summary>
        /// 创建引用类型对象池
        /// </summary>
        public IReferencePool<T> CreateReferencePool<T>(
            Func<T> createFunc,
            Action<T> onSpawn = null,
            Action<T> onRecycle = null,
            Action<T> onDestroy = null,
            int initialCapacity = 5,
            int maxSize = 100,
            bool isDynamic = true) where T : ReferencePoolable
        {
            var type = typeof(T);
            
            // 检查是否已存在
            if (_referencePools.TryGetValue(type, out var existingPool))
            {
                return (IReferencePool<T>)existingPool;
            }

            // 创建对象池
            IReferencePool<T> pool = isDynamic ?
                new DynamicReferencePool<T>(createFunc, onSpawn, onRecycle, onDestroy, initialCapacity, maxSize) :
                new FixedReferencePool<T>(createFunc, onSpawn, onRecycle, onDestroy, initialCapacity);
            
            _referencePools[type] = pool;
            return pool;
        }
        
        /// <summary>
        /// 获取引用类型对象池
        /// </summary>
        public IReferencePool<T> GetReferencePool<T>() where T : ReferencePoolable
        {
            if (_referencePools.TryGetValue(typeof(T), out var pool))
            {
                return (IReferencePool<T>)pool;
            }
            
            Debug.LogError($"No reference pool registered for type {typeof(T).Name}");
            return null;
        }
        
        /// <summary>
        /// 从引用类型对象池获取对象
        /// </summary>
        public T SpawnFromReferencePool<T>() where T : ReferencePoolable
        {
            var pool = GetReferencePool<T>();
            return pool?.Spawn();
        }
        
        /// <summary>
        /// 回收对象到引用类型对象池
        /// </summary>
        public void RecycleToReferencePool<T>(T obj) where T : ReferencePoolable
        {
            if (obj == null) return;
            
            var pool = GetReferencePool<T>();
            if (pool != null)
            {
                pool.Recycle(obj);
            }
            else
            {
                Debug.LogError($"No reference pool found for object of type {obj.GetType().Name}");
            }
        }
        
        /// <summary>
        /// 销毁引用类型对象池
        /// </summary>
        public void DestroyReferencePool<T>() where T : class
        {
            if (_referencePools.TryGetValue(typeof(T), out var pool))
            {
                pool.Clear();
                _referencePools.Remove(typeof(T));
            }
        }
        
        #endregion
        
        #region GameObject对象池操作
        
        /// <summary>
        /// 创建GameObject对象池
        /// </summary>
        public IGameObjectPool<T> CreateGameObjectPool<T>(
            GameObjectPoolable prefab,
            Func<T> createFunc,
            Action<T> onSpawn = null,
            Action<T> onRecycle = null,
            Action<T> onDestroy = null,
            int initialCapacity = 5,
            int maxSize = 100,
            bool isDynamic = true,
            Transform poolRoot = null) where T : GameObjectPoolable
        {
            int prefabId = prefab.GetInstanceID();
            
            // 检查是否已存在
            if (_gameObjectPools.TryGetValue(prefabId, out var existingPool))
            {
                return (IGameObjectPool<T>)existingPool;
            }

            // 创建对象池
            IGameObjectPool<T> pool = isDynamic ?
                new DynamicGameObjectPool<T>(createFunc, onSpawn, onRecycle, onDestroy, initialCapacity, maxSize, poolRoot) :
                new FixedGameObjectPool<T>(createFunc, onSpawn, onRecycle, onDestroy, initialCapacity, poolRoot);
            
            _gameObjectPools[prefabId] = pool;
            return pool;
        }
        
        /// <summary>
        /// 获取GameObject对象池
        /// </summary>
        public IGameObjectPool<T> GetGameObjectPool<T>(GameObjectPoolable prefab) where T : GameObjectPoolable
        {
            int prefabId = prefab.GetInstanceID();
            if (_gameObjectPools.TryGetValue(prefabId, out var pool))
            {
                // 检查类型兼容性
                var poolType = pool.PoolType;
                var targetType = typeof(T);
                
                if (targetType == poolType || poolType.IsAssignableFrom(targetType))
                {
                    return (IGameObjectPool<T>)pool;
                }
                else
                {
                    Debug.LogError($"Type mismatch: Pool stores {poolType.Name}, but trying to access as {targetType.Name}");
                    return null;
                }
            }
            
            Debug.LogError($"No GameObject pool registered for prefab {prefab.name} (ID: {prefabId})");
            return null;
        }
        
        /// <summary>
        /// 从GameObject对象池获取对象
        /// </summary>
        public T SpawnFromGameObjectPool<T>(GameObjectPoolable prefab) where T : GameObjectPoolable
        {
            var pool = GetGameObjectPool<T>(prefab);
            return pool?.Spawn();
        }
        
        /// <summary>
        /// 回收对象到GameObject对象池
        /// </summary>
        public void RecycleToGameObjectPool<T>(T obj, GameObjectPoolable prefab) where T : GameObjectPoolable
        {
            if (obj == null) return;
            
            var pool = GetGameObjectPool<T>(prefab);
            if (pool != null)
            {
                pool.Recycle(obj);
            }
            else
            {
                Debug.LogError($"No GameObject pool found for prefab {prefab.name} when recycling {obj.GetType().Name}");
            }
        }
        
        /// <summary>
        /// 回收GameObject对象到对象池（非泛型版本）
        /// </summary>
        public void RecycleToGameObjectPool(GameObjectPoolable obj, GameObjectPoolable prefab)
        {
            if (obj == null || prefab == null) return;
            
            int prefabId = prefab.GetInstanceID();
            if (_gameObjectPools.TryGetValue(prefabId, out var pool))
            {
                // 使用反射调用池的Recycle方法
                var recycleMethod = pool.GetType().GetMethod("Recycle");
                if (recycleMethod != null)
                {
                    recycleMethod.Invoke(pool, new object[] { obj });
                }
                else
                {
                    Debug.LogError($"Pool does not have Recycle method for object {obj.GetType().Name}");
                }
            }
            else
            {
                Debug.LogError($"No GameObject pool found for prefab {prefab.name} when recycling {obj.GetType().Name}");
            }
        }
        
        /// <summary>
        /// 销毁GameObject对象池
        /// </summary>
        public void DestroyGameObjectPool<T>(GameObjectPoolable prefab) where T : GameObjectPoolable
        {
            int prefabId = prefab.GetInstanceID();
            if (_gameObjectPools.TryGetValue(prefabId, out var pool))
            {
                pool.Clear();
                _gameObjectPools.Remove(prefabId);
            }
        }
        
        #endregion
        
        #region 通用功能接口
        
        /// <summary>
        /// 智能回收：自动判断是引用类型对象池还是GameObject对象池
        /// </summary>
        public void Recycle<T>(T obj, GameObjectPoolable prefab = null) where T : IPoolable
        {
            if (obj == null) return;
            
            if (obj is GameObjectPoolable poolableObj && prefab != null)
            {
                // 使用GameObject对象池的非泛型版本
                RecycleToGameObjectPool(poolableObj, prefab);
            }
            else
            {
                // 使用引用类型对象池
                RecycleToReferencePool(obj as ReferencePoolable);
            }
        }
        
        /// <summary>
        /// 获取引用类型对象池的所有存储对象
        /// </summary>
        public List<T> GetAllReferencePoolObjects<T>() where T : ReferencePoolable
        {
            var pool = GetReferencePool<T>();
            if (pool != null && pool is ReferenceObjectPool<T> referencePool)
            {
                return referencePool.GetAllPooledObjects();
            }
            return new List<T>();
        }
        
        /// <summary>
        /// 获取GameObject对象池的所有存储对象
        /// </summary>
        public List<T> GetAllGameObjectPoolObjects<T>(GameObjectPoolable prefab) where T : GameObjectPoolable
        {
            var pool = GetGameObjectPool<T>(prefab);
            if (pool != null && pool is GameObjectPool<T> gameObjectPool)
            {
                return gameObjectPool.GetAllPooledObjects();
            }
            return new List<T>();
        }
        
        /// <summary>
        /// 预热引用类型对象池
        /// </summary>
        public void PrewarmReferencePool<T>(int count) where T : ReferencePoolable
        {
            var pool = GetReferencePool<T>();
            if (pool != null && pool is ReferenceObjectPool<T> referencePool)
            {
                referencePool.Prewarm(count);
            }
        }
        
        /// <summary>
        /// 预热GameObject对象池
        /// </summary>
        public void PrewarmGameObjectPool<T>(GameObjectPoolable prefab, int count) where T : GameObjectPoolable
        {
            var pool = GetGameObjectPool<T>(prefab);
            if (pool != null && pool is GameObjectPool<T> gameObjectPool)
            {
                gameObjectPool.Prewarm(count);
            }
        }
        
        /// <summary>
        /// 获取引用类型对象池统计信息
        /// </summary>
        public PoolStatistics GetReferencePoolStatistics<T>() where T : ReferencePoolable
        {
            var pool = GetReferencePool<T>();
            return pool?.Statistics ?? new PoolStatistics();
        }
        
        /// <summary>
        /// 获取GameObject对象池统计信息
        /// </summary>
        public PoolStatistics GetGameObjectPoolStatistics<T>(GameObjectPoolable prefab) where T : GameObjectPoolable
        {
            var pool = GetGameObjectPool<T>(prefab);
            return pool?.Statistics ?? new PoolStatistics();
        }
        
        /// <summary>
        /// 检查引用类型对象池是否存在
        /// </summary>
        public bool HasReferencePool<T>() where T : class
        {
            return _referencePools.ContainsKey(typeof(T));
        }
        
        /// <summary>
        /// 检查GameObject对象池是否存在
        /// </summary>
        public bool HasGameObjectPool<T>(GameObjectPoolable prefab) where T : GameObjectPoolable
        {
            return _gameObjectPools.ContainsKey(prefab.GetInstanceID());
        }
        
        
        /// <summary>
        /// 获取所有引用类型对象池名称
        /// </summary>
        public List<string> GetAllReferencePoolNames()
        {
            return _referencePools.Keys.AsValueEnumerable().Select(t => t.Name).ToList();
        }
        
        /// <summary>
        /// 获取所有GameObject对象池信息
        /// </summary>
        public Dictionary<string, int> GetAllGameObjectPoolInfo()
        {
            var info = new Dictionary<string, int>();
            foreach (var kvp in _gameObjectPools)
            {
                var prefab = FindPrefabById(kvp.Key);
                info[prefab != null ? prefab.name : $"Unknown_{kvp.Key}"] = kvp.Value.Count;
            }
            return info;
        }
        
        #endregion

        /// <summary>
        /// 清空所有对象池
        /// </summary>
        public void ClearAllPools()
        {
            foreach (var pool in _referencePools.Values)
            {
                pool.Clear();
            }
            foreach (var pool in _gameObjectPools.Values)
            {
                pool.Clear();
            }

            _referencePools.Clear();
            _gameObjectPools.Clear();
        }

        /// <summary>
        /// 获取所有对象池统计信息
        /// </summary>
        public Dictionary<string, PoolStatistics> GetAllPoolStatistics()
        {
            var stats = new Dictionary<string, PoolStatistics>();
            
            // 引用类型对象池统计
            foreach (var kvp in _referencePools)
            {
                stats[$"Reference_{kvp.Key.Name}"] = kvp.Value.Statistics;
            }
            
            // GameObject对象池统计
            foreach (var kvp in _gameObjectPools)
            {
                var prefab = FindPrefabById(kvp.Key);
                stats[$"GameObject_{prefab?.name ?? kvp.Key.ToString()}"] = kvp.Value.Statistics;
            }
            
            return stats;
        }
        
        /// <summary>
        /// 调试：打印所有对象池信息
        /// </summary>
        public void DebugPrintAllPools()
        {
            Debug.Log("=== 对象池调试信息 ===");
            
            Debug.Log("引用类型对象池:");
            foreach (var kvp in _referencePools)
            {
                Debug.Log($"  {kvp.Key.Name}: {kvp.Value.Count} 个对象");
            }
            
            Debug.Log("GameObject对象池:");
            foreach (var kvp in _gameObjectPools)
            {
                var prefab = FindPrefabById(kvp.Key);
                Debug.Log($"  {prefab?.name ?? kvp.Key.ToString()}: {kvp.Value.Count} 个对象");
            }
            
            Debug.Log("=====================");
        }
        
        /// <summary>
        /// 根据ID查找预制体（用于调试）
        /// </summary>
        private GameObjectPoolable FindPrefabById(int id)
        {
            // 这里可以通过Resources或其他方式查找预制体
            // 暂时返回null，实际使用时可以扩展
            return null;
        }

        private void OnDestroy()
        {
            ClearAllPools();
        }
        

        internal override void Update(float elapseSeconds, float realElapseSeconds)
        {
            // 定期处理对象池策略
        }

        internal override void Shutdown()
        {
            ClearAllPools();
        }
    }
}